From c11ae185aa417bf261af83f0bbe6cea14a8e9c01 Mon Sep 17 00:00:00 2001 From: Alexander Richardson Date: Tue, 27 Feb 2018 11:15:11 +0000 Subject: [PATCH] Make the LLParser accept call instructions of variables in the program AS Summary: Since r325479 the DataLayout includes a program address space. However, it is not possible to use `call %foo` if foo is a `i8(...) addrspace(200)` and the DataLayout specifies address space 200 as the address space for functions. With this change the IR parser will still accept variables in the program address space as well as address space 0 for call and invoke functions. Reviewers: pcc, arsenm, bjope, dylanmckay, theraven Reviewed By: dylanmckay Subscribers: wdng, llvm-commits Differential Revision: https://reviews.llvm.org/D43645 llvm-svn: 326188 --- llvm/lib/AsmParser/LLParser.cpp | 51 +++++++++++++++------- llvm/lib/AsmParser/LLParser.h | 6 +-- .../Assembler/call-nonzero-program-addrspace-2.ll | 11 +++++ .../Assembler/call-nonzero-program-addrspace.ll | 13 ++++++ .../Assembler/invoke-nonzero-program-addrspace.ll | 18 ++++++++ 5 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 llvm/test/Assembler/call-nonzero-program-addrspace-2.ll create mode 100644 llvm/test/Assembler/call-nonzero-program-addrspace.ll create mode 100644 llvm/test/Assembler/invoke-nonzero-program-addrspace.ll diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 42c5798..29e6b07 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2612,11 +2612,24 @@ bool LLParser::PerFunctionState::FinishFunction() { return false; } +static bool isValidVariableType(Module *M, Type *Ty, Value *Val, bool IsCall) { + if (Val->getType() == Ty) + return true; + // For calls we also accept variables in the program address space + if (IsCall && isa(Ty)) { + Type *TyInProgAS = cast(Ty)->getElementType()->getPointerTo( + M->getDataLayout().getProgramAddressSpace()); + if (Val->getType() == TyInProgAS) + return true; + } + return false; +} + /// GetVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, - LocTy Loc) { + LocTy Loc, bool IsCall) { // Look this name up in the normal function symbol table. Value *Val = F.getValueSymbolTable()->lookup(Name); @@ -2630,7 +2643,8 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { - if (Val->getType() == Ty) return Val; + if (isValidVariableType(P.M, Ty, Val, IsCall)) + return Val; if (Ty->isLabelTy()) P.Error(Loc, "'%" + Name + "' is not a basic block"); else @@ -2657,7 +2671,8 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, return FwdVal; } -Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc) { +Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc, + bool IsCall) { // Look this name up in the normal function symbol table. Value *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr; @@ -2671,7 +2686,8 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc) { // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { - if (Val->getType() == Ty) return Val; + if (isValidVariableType(P.M, Ty, Val, IsCall)) + return Val; if (Ty->isLabelTy()) P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block"); else @@ -2762,13 +2778,13 @@ bool LLParser::PerFunctionState::SetInstName(int NameID, /// forward reference record if needed. BasicBlock *LLParser::PerFunctionState::GetBB(const std::string &Name, LocTy Loc) { - return dyn_cast_or_null(GetVal(Name, - Type::getLabelTy(F.getContext()), Loc)); + return dyn_cast_or_null( + GetVal(Name, Type::getLabelTy(F.getContext()), Loc, /*IsCall=*/false)); } BasicBlock *LLParser::PerFunctionState::GetBB(unsigned ID, LocTy Loc) { - return dyn_cast_or_null(GetVal(ID, - Type::getLabelTy(F.getContext()), Loc)); + return dyn_cast_or_null( + GetVal(ID, Type::getLabelTy(F.getContext()), Loc, /*IsCall=*/false)); } /// DefineBB - Define the specified basic block, which is either named or @@ -3387,7 +3403,7 @@ bool LLParser::ParseGlobalValue(Type *Ty, Constant *&C) { ValID ID; Value *V = nullptr; bool Parsed = ParseValID(ID) || - ConvertValIDToValue(Ty, ID, V, nullptr); + ConvertValIDToValue(Ty, ID, V, nullptr, /*IsCall=*/false); if (V && !(C = dyn_cast(V))) return Error(ID.Loc, "global values must be constants"); return Parsed; @@ -4729,18 +4745,18 @@ bool LLParser::ParseMetadata(Metadata *&MD, PerFunctionState *PFS) { //===----------------------------------------------------------------------===// bool LLParser::ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, - PerFunctionState *PFS) { + PerFunctionState *PFS, bool IsCall) { if (Ty->isFunctionTy()) return Error(ID.Loc, "functions are not values, refer to them as pointers"); switch (ID.Kind) { case ValID::t_LocalID: if (!PFS) return Error(ID.Loc, "invalid use of function-local name"); - V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc); + V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc, IsCall); return V == nullptr; case ValID::t_LocalName: if (!PFS) return Error(ID.Loc, "invalid use of function-local name"); - V = PFS->GetVal(ID.StrVal, Ty, ID.Loc); + V = PFS->GetVal(ID.StrVal, Ty, ID.Loc, IsCall); return V == nullptr; case ValID::t_InlineAsm: { if (!ID.FTy || !InlineAsm::Verify(ID.FTy, ID.StrVal2)) @@ -4856,7 +4872,7 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) { case ValID::t_ConstantStruct: case ValID::t_PackedConstantStruct: { Value *V; - if (ConvertValIDToValue(Ty, ID, V, /*PFS=*/nullptr)) + if (ConvertValIDToValue(Ty, ID, V, /*PFS=*/nullptr, /*IsCall=*/false)) return true; assert(isa(V) && "Expected a constant value"); C = cast(V); @@ -4873,7 +4889,8 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) { bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS) { V = nullptr; ValID ID; - return ParseValID(ID, PFS) || ConvertValIDToValue(Ty, ID, V, PFS); + return ParseValID(ID, PFS) || + ConvertValIDToValue(Ty, ID, V, PFS, /*IsCall=*/false); } bool LLParser::ParseTypeAndValue(Value *&V, PerFunctionState *PFS) { @@ -5626,7 +5643,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) { // Look up the callee. Value *Callee; - if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS)) + if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, + /*IsCall=*/true)) return true; // Set up the Attribute for the function. @@ -6217,7 +6235,8 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, // Look up the callee. Value *Callee; - if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS)) + if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, + /*IsCall=*/true)) return true; // Set up the Attribute for the function. diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index a3252ff..79428d4 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -358,8 +358,8 @@ namespace llvm { /// GetVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. - Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc); - Value *GetVal(unsigned ID, Type *Ty, LocTy Loc); + Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc, bool IsCall); + Value *GetVal(unsigned ID, Type *Ty, LocTy Loc, bool IsCall); /// SetInstName - After an instruction is parsed and inserted into its /// basic block, this installs its name. @@ -381,7 +381,7 @@ namespace llvm { }; bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, - PerFunctionState *PFS); + PerFunctionState *PFS, bool IsCall); bool parseConstantValue(Type *Ty, Constant *&C); bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); diff --git a/llvm/test/Assembler/call-nonzero-program-addrspace-2.ll b/llvm/test/Assembler/call-nonzero-program-addrspace-2.ll new file mode 100644 index 0000000..ed8546c --- /dev/null +++ b/llvm/test/Assembler/call-nonzero-program-addrspace-2.ll @@ -0,0 +1,11 @@ +; RUN: llvm-as %s -data-layout=P200 -o /dev/null +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; Check that numbered variables in a nonzero program address space 200 can be used in a call instruction + +define i8 @test_unnamed(i8(i32)*, i8(i32) addrspace(200)*) { + %first = call i8 %0(i32 0) ; this is fine + %second = call i8 %1(i32 0) ; this is also fine if it's the program AS + ; CHECK: call-nonzero-program-addrspace-2.ll:[[@LINE-1]]:21: error: '%1' defined with type 'i8 (i32) addrspace(200)*' + ret i8 0 +} diff --git a/llvm/test/Assembler/call-nonzero-program-addrspace.ll b/llvm/test/Assembler/call-nonzero-program-addrspace.ll new file mode 100644 index 0000000..1d1a224 --- /dev/null +++ b/llvm/test/Assembler/call-nonzero-program-addrspace.ll @@ -0,0 +1,13 @@ +; RUN: llvm-as %s -data-layout=P200 -o /dev/null +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; Check that variables in a nonzero program address space 200 can be used in a call instruction + +define i8 @test(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) { + %first = call i8 %fnptr0(i32 0) ; this is fine + %second = call i8 %fnptr200(i32 0) ; this is also fine if it's the program AS + ; CHECK: call-nonzero-program-addrspace.ll:[[@LINE-1]]:21: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' + ret i8 0 +} + +declare i32 @__gxx_personality_v0(...) diff --git a/llvm/test/Assembler/invoke-nonzero-program-addrspace.ll b/llvm/test/Assembler/invoke-nonzero-program-addrspace.ll new file mode 100644 index 0000000..4438845 --- /dev/null +++ b/llvm/test/Assembler/invoke-nonzero-program-addrspace.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as %s -data-layout=P200 -o /dev/null +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; Check that variables in a nonzero program address space 200 can be used in a invoke instruction + +define i8 @test_invoke(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) personality i32 (...)* @__gxx_personality_v0 { + %first = invoke i8 %fnptr0(i32 0) to label %ok unwind label %lpad ; this is fine + %second = invoke i8 %fnptr200(i32 0) to label %ok unwind label %lpad ; this is also fine if it's the program AS + ; CHECK: invoke-nonzero-program-addrspace.ll:[[@LINE-1]]:23: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' +ok: + ret i8 0 +lpad: + %exn = landingpad {i8*, i32} + cleanup + unreachable +} + +declare i32 @__gxx_personality_v0(...) -- 2.7.4