From 9e367bd69b0d2523237e204b43301e59a5badb29 Mon Sep 17 00:00:00 2001 From: Craig Disselkoen Date: Fri, 25 Sep 2020 14:34:23 -0700 Subject: [PATCH] C API: functions to get mask of a ShuffleVector This commit fixes a regression (from LLVM 10 to LLVM 11 RC3) in the LLVM C API. Previously, commit 1ee6ec2bf removed the mask operand from the ShuffleVector instruction, storing the mask data separately in the instruction instead; this reduced the number of operands of ShuffleVector from 3 to 2. AFAICT, this change unintentionally caused a regression in the LLVM C API. Specifically, it is no longer possible to get the mask of a ShuffleVector instruction through the C API. This patch introduces new functions which together allow a C API user to get the mask of a ShuffleVector instruction, restoring the functionality which was previously available through LLVMGetOperand(). This patch also adds tests for this change to the llvm-c-test executable, which involved adding support for InsertElement, ExtractElement, and ShuffleVector itself (as well as constant vectors) to echo.cpp. Previously, vector operations weren't tested at all in echo.ll. I also fixed some typos in comments and help-text nearby these changes, which I happened to spot while developing this patch. Since the typo fixes are technically unrelated other than being in the same files, I'm happy to take them out if you'd rather they not be included in the patch. Differential Revision: https://reviews.llvm.org/D88190 (cherry picked from commit 51cad041e0cb26597c7ccc0fbfaa349b8fffbcda) --- llvm/include/llvm-c/Core.h | 15 +++++- llvm/lib/IR/Core.cpp | 14 ++++++ llvm/test/Bindings/llvm-c/echo.ll | 18 +++++++ llvm/tools/llvm-c-test/echo.cpp | 80 ++++++++++++++++++++++++++----- llvm/tools/llvm-c-test/main.c | 9 ++-- 5 files changed, 119 insertions(+), 17 deletions(-) diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h index 2c7b4c6eff107a..34d23146be40fb 100644 --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -3636,7 +3636,7 @@ void LLVMAddDestination(LLVMValueRef IndirectBr, LLVMBasicBlockRef Dest); /* Get the number of clauses on the landingpad instruction */ unsigned LLVMGetNumClauses(LLVMValueRef LandingPad); -/* Get the value of the clause at idnex Idx on the landingpad instruction */ +/* Get the value of the clause at index Idx on the landingpad instruction */ LLVMValueRef LLVMGetClause(LLVMValueRef LandingPad, unsigned Idx); /* Add a catch or filter clause to the landingpad instruction */ @@ -3937,6 +3937,19 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMAtomicOrdering FailureOrdering, LLVMBool SingleThread); +/** + * Get the number of elements in the mask of a ShuffleVector instruction. + */ +unsigned LLVMGetNumMaskElements(LLVMValueRef ShuffleVectorInst); + +/** + * Get the mask value at position Elt in the mask of a ShuffleVector + * instruction. Return LLVMUndefMaskElem if the mask value is undef at that + * position. + */ +int LLVMGetMaskValue(LLVMValueRef ShuffleVectorInst, unsigned Elt); +extern const int LLVMUndefMaskElem; + LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst); void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread); diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 6f3bbc80d4fd56..9caaea4b1f7a06 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -3952,6 +3952,20 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr, singleThread ? SyncScope::SingleThread : SyncScope::System)); } +unsigned LLVMGetNumMaskElements(LLVMValueRef SVInst) { + Value *P = unwrap(SVInst); + ShuffleVectorInst *I = cast(P); + return I->getShuffleMask().size(); +} + +int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) { + Value *P = unwrap(SVInst); + ShuffleVectorInst *I = cast(P); + return I->getMaskValue(Elt); +} +const int LLVMUndefMaskElem = + -1; // not actually accessible as ShuffleVectorInst::UndefMaskElem, so we + // hardcode it here LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { Value *P = unwrap(AtomicInst); diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll index 510798592b9d3d..5494170f3cd652 100644 --- a/llvm/test/Bindings/llvm-c/echo.ll +++ b/llvm/test/Bindings/llvm-c/echo.ll @@ -156,6 +156,24 @@ define void @memops(i8* %ptr) { ret void } +define i32 @vectorops(i32, i32) { + %a = insertelement <4 x i32> undef, i32 %0, i32 0 + %b = insertelement <4 x i32> %a, i32 %1, i32 2 + %c = shufflevector <4 x i32> %b, <4 x i32> undef, <4 x i32> zeroinitializer + %d = shufflevector <4 x i32> %c, <4 x i32> %b, <4 x i32> + %e = add <4 x i32> %d, %a + %f = mul <4 x i32> %e, %b + %g = xor <4 x i32> %f, %d + %h = or <4 x i32> %f, %e + %i = lshr <4 x i32> %h, + %j = shl <4 x i32> %i, + %k = shufflevector <4 x i32> %j, <4 x i32> %i, <4 x i32> + %m = shufflevector <4 x i32> %k, <4 x i32> undef, <1 x i32> + %n = shufflevector <4 x i32> %j, <4 x i32> undef, <8 x i32> + %p = extractelement <8 x i32> %n, i32 5 + ret i32 %p +} + declare void @personalityFn() define void @exn() personality void ()* @personalityFn { diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp index b254da28ddc4bf..b404048749d393 100644 --- a/llvm/tools/llvm-c-test/echo.cpp +++ b/llvm/tools/llvm-c-test/echo.cpp @@ -30,7 +30,7 @@ template struct CAPIDenseMap {}; // The default DenseMapInfo require to know about pointer alignment. -// Because the C API uses opaques pointer types, their alignment is unknown. +// Because the C API uses opaque pointer types, their alignment is unknown. // As a result, we need to roll out our own implementation. template struct CAPIDenseMap { @@ -306,7 +306,7 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) { return LLVMConstArray(LLVMGetElementType(Ty), Elts.data(), EltCount); } - // Try contant data array + // Try constant data array if (LLVMIsAConstantDataArray(Cst)) { check_value_kind(Cst, LLVMConstantDataArrayValueKind); LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); @@ -357,9 +357,32 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) { report_fatal_error("ConstantFP is not supported"); } - // This kind of constant is not supported + // Try ConstantVector + if (LLVMIsAConstantVector(Cst)) { + check_value_kind(Cst, LLVMConstantVectorValueKind); + LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); + unsigned EltCount = LLVMGetVectorSize(Ty); + SmallVector Elts; + for (unsigned i = 0; i < EltCount; i++) + Elts.push_back(clone_constant(LLVMGetOperand(Cst, i), M)); + return LLVMConstVector(Elts.data(), EltCount); + } + + // Try ConstantDataVector + if (LLVMIsAConstantDataVector(Cst)) { + check_value_kind(Cst, LLVMConstantDataVectorValueKind); + LLVMTypeRef Ty = TypeCloner(M).Clone(Cst); + unsigned EltCount = LLVMGetVectorSize(Ty); + SmallVector Elts; + for (unsigned i = 0; i < EltCount; i++) + Elts.push_back(clone_constant(LLVMGetElementAsConstant(Cst, i), M)); + return LLVMConstVector(Elts.data(), EltCount); + } + + // At this point, if it's not a constant expression, it's a kind of constant + // which is not supported if (!LLVMIsAConstantExpr(Cst)) - report_fatal_error("Expected a constant expression"); + report_fatal_error("Unsupported constant kind"); // At this point, it must be a constant expression check_value_kind(Cst, LLVMConstantExprValueKind); @@ -370,7 +393,8 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) { return LLVMConstBitCast(clone_constant(LLVMGetOperand(Cst, 0), M), TypeCloner(M).Clone(Cst)); default: - fprintf(stderr, "%d is not a supported opcode\n", Op); + fprintf(stderr, "%d is not a supported opcode for constant expressions\n", + Op); exit(-1); } } @@ -443,7 +467,7 @@ struct FunCloner { auto i = VMap.find(Src); if (i != VMap.end()) { // If we have a hit, it means we already generated the instruction - // as a dependancy to somethign else. We need to make sure + // as a dependency to something else. We need to make sure // it is ordered properly. auto I = i->second; LLVMInstructionRemoveFromParent(I); @@ -746,8 +770,10 @@ struct FunCloner { } case LLVMExtractValue: { LLVMValueRef Agg = CloneValue(LLVMGetOperand(Src, 0)); - if (LLVMGetNumIndices(Src) != 1) - report_fatal_error("Expected only one indice"); + if (LLVMGetNumIndices(Src) > 1) + report_fatal_error("ExtractValue: Expected only one index"); + else if (LLVMGetNumIndices(Src) < 1) + report_fatal_error("ExtractValue: Expected an index"); auto I = LLVMGetIndices(Src)[0]; Dst = LLVMBuildExtractValue(Builder, Agg, I, Name); break; @@ -755,12 +781,44 @@ struct FunCloner { case LLVMInsertValue: { LLVMValueRef Agg = CloneValue(LLVMGetOperand(Src, 0)); LLVMValueRef V = CloneValue(LLVMGetOperand(Src, 1)); - if (LLVMGetNumIndices(Src) != 1) - report_fatal_error("Expected only one indice"); + if (LLVMGetNumIndices(Src) > 1) + report_fatal_error("InsertValue: Expected only one index"); + else if (LLVMGetNumIndices(Src) < 1) + report_fatal_error("InsertValue: Expected an index"); auto I = LLVMGetIndices(Src)[0]; Dst = LLVMBuildInsertValue(Builder, Agg, V, I, Name); break; } + case LLVMExtractElement: { + LLVMValueRef Agg = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef Index = CloneValue(LLVMGetOperand(Src, 1)); + Dst = LLVMBuildExtractElement(Builder, Agg, Index, Name); + break; + } + case LLVMInsertElement: { + LLVMValueRef Agg = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef V = CloneValue(LLVMGetOperand(Src, 1)); + LLVMValueRef Index = CloneValue(LLVMGetOperand(Src, 2)); + Dst = LLVMBuildInsertElement(Builder, Agg, V, Index, Name); + break; + } + case LLVMShuffleVector: { + LLVMValueRef Agg0 = CloneValue(LLVMGetOperand(Src, 0)); + LLVMValueRef Agg1 = CloneValue(LLVMGetOperand(Src, 1)); + SmallVector MaskElts; + unsigned NumMaskElts = LLVMGetNumMaskElements(Src); + for (unsigned i = 0; i < NumMaskElts; i++) { + int Val = LLVMGetMaskValue(Src, i); + if (Val == LLVMUndefMaskElem) { + MaskElts.push_back(LLVMGetUndef(LLVMInt64Type())); + } else { + MaskElts.push_back(LLVMConstInt(LLVMInt64Type(), Val, true)); + } + } + LLVMValueRef Mask = LLVMConstVector(MaskElts.data(), NumMaskElts); + Dst = LLVMBuildShuffleVector(Builder, Agg0, Agg1, Mask, Name); + break; + } case LLVMFreeze: { LLVMValueRef Arg = CloneValue(LLVMGetOperand(Src, 0)); Dst = LLVMBuildFreeze(Builder, Arg, Name); @@ -1102,7 +1160,7 @@ static void clone_symbols(LLVMModuleRef Src, LLVMModuleRef M) { LLVMGlobalSetMetadata(G, Kind, MD); } LLVMDisposeValueMetadataEntries(AllMetadata); - + LLVMSetGlobalConstant(G, LLVMIsGlobalConstant(Cur)); LLVMSetThreadLocal(G, LLVMIsThreadLocal(Cur)); LLVMSetExternallyInitialized(G, LLVMIsExternallyInitialized(Cur)); diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c index 0be48930f0b656..5e8adb45d691e4 100644 --- a/llvm/tools/llvm-c-test/main.c +++ b/llvm/tools/llvm-c-test/main.c @@ -36,10 +36,10 @@ static void print_usage(void) { fprintf(stderr, " * --targets-list\n"); fprintf(stderr, " List available targets\n\n"); fprintf(stderr, " * --object-list-sections\n"); - fprintf(stderr, " Read object file form stdin - list sections\n\n"); + fprintf(stderr, " Read object file from stdin - list sections\n\n"); fprintf(stderr, " * --object-list-symbols\n"); fprintf(stderr, - " Read object file form stdin - list symbols (like nm)\n\n"); + " Read object file from stdin - list symbols (like nm)\n\n"); fprintf(stderr, " * --disassemble\n"); fprintf(stderr, " Read lines of triple, hex ascii machine code from stdin " "- print disassembly\n\n"); @@ -48,11 +48,10 @@ static void print_usage(void) { stderr, " Read lines of name, rpn from stdin - print generated module\n\n"); fprintf(stderr, " * --echo\n"); - fprintf(stderr, - " Read bitcode file form stdin - print it back out\n\n"); + fprintf(stderr, " Read bitcode file from stdin - print it back out\n\n"); fprintf(stderr, " * --test-diagnostic-handler\n"); fprintf(stderr, - " Read bitcode file form stdin with a diagnostic handler set\n\n"); + " Read bitcode file from stdin with a diagnostic handler set\n\n"); fprintf(stderr, " * --test-dibuilder\n"); fprintf(stderr, " Run tests for the DIBuilder C API - print generated module\n\n");